#ifndef __EPOLL_SERVER_HPP__
#define __EPOLL_SERVER_HPP__

#include <iostream>
#include <string>
#include <functional>
#include <cassert>
#include "Log.hpp"
#include "Sock.hpp"
#include "Epoll.hpp"

namespace ns_epoll
{
    const static int default_port = 8080;
    const static int gnum = 64;
    class EpollServer // 这里先只处理读取
    {
        using func_t = std::function<void(std::string)>;
    public:
        EpollServer(func_t HandlerRequest, const int &port = default_port)
            : _port(port), _revs_num(gnum), _HandlerRequest(HandlerRequest)
        {
            _revs = new struct epoll_event[_revs_num]; // 1. 申请对应的空间
            _listensock = Sock::Socket(); // 2. 创建listensock
            Sock::Bind(_listensock, _port);
            Sock::Listen(_listensock);
            _epfd = Epoll::CreateEpoll(); // 3. 创建epoll模型
            logMessage(DEBUG, "init success, listensock: %d, epfd: %d", _listensock, _epfd);
            // 4. 将listensock，先添加到epoll中，让epoll管理起来
            if (!Epoll::CtlEpoll(_epfd, EPOLL_CTL_ADD, _listensock, EPOLLIN))
                exit(6);
            logMessage(DEBUG, "add listensock to epoll success.");
        }
        void Accepter(int listensock)
        {
            std::string clientip;
            uint16_t clientport;
            int sock = Sock::Accept(listensock, &clientip, &clientport);
            if (sock < 0)
            {
                logMessage(WARNING, "accept error");
                return;
            }
            // 不能直接读取，因为并不清楚底层是否有数据
            if (!Epoll::CtlEpoll(_epfd, EPOLL_CTL_ADD, sock, EPOLLIN)) // 将新的sock添加给epoll
                return;
            logMessage(DEBUG, "add new sock : %d to epoll success", sock);
        }
        void Recver(int sock)
        {
            char buffer[10240];  // 1. 读取数据
            ssize_t n = recv(sock, buffer, sizeof(buffer) - 1, 0);
            if (n > 0) // 假设这里就是读到了一个完整的报文
            {
                buffer[n] = 0;
                _HandlerRequest(buffer); // 2. 用服务端传进来的方法处理数据
            }
            else if (n == 0)
            {
                bool res = Epoll::CtlEpoll(_epfd, EPOLL_CTL_DEL, sock, 0); // 1. 先在epoll中去掉对sock的关心
                assert(res);
                (void)res;
                close(sock); // 2. 再close文件
                logMessage(NORMAL, "client %d quit, me too...", sock);
            }
            else
            {
                bool res = Epoll::CtlEpoll(_epfd, EPOLL_CTL_DEL, sock, 0); // 1. 先在epoll中去掉对sock的关心
                assert(res);
                (void)res;
                close(sock); // 2. 再close文件
                logMessage(NORMAL, "client recv %d error, close error sock", sock);
            }
        }
        void HandlerEvents(int n)
        {
            assert(n > 0);
            for (int i = 0; i < n; i++)
            {
                uint32_t revents = _revs[i].events;
                int sock = _revs[i].data.fd;
                if (revents & EPOLLIN) // 读事件就绪
                {
                    if (sock == _listensock)
                    {
                        Accepter(_listensock); // 1. listensock 就绪
                    }
                    else
                    {
                        Recver(sock); // 2. 一般sock 就绪 - read
                    }
                }
                if (revents & EPOLLOUT)
                {
                    // 这里不处理
                }
            }
        }
        void LoopOnce(int timeout)
        {
            int n = Epoll::WaitEpoll(_epfd, _revs, _revs_num, timeout); // 封装意义不大还是和上面一样封装了
            // 细节1：如果底层就绪的sock非常多，revs承装不下的话 -> 一次拿不完，就下一次再拿
            // 担心拿不完的话 -> if(n == _revs_num) // 可以扩容，这里不处理
            // 细节2：关于epoll_wait的返回值问题：有几个fd上的事件就绪，就返回几,
            // epoll返回的时候，会将所有就绪的event按照顺序放入到revs数组中, 一共有返回值个->用来遍历就绪队列
            switch (n)
            {
            case 0:
                logMessage(DEBUG, "timeout..."); // 3, 4
                break;
            case -1:
                logMessage(WARNING, "epoll wait error: %s", strerror(errno));
                break;
            default:
                // 等待成功
                logMessage(DEBUG, "get a event");
                HandlerEvents(n);
                break;
            }
        }
        void Start()
        {
            int timeout = -1; // -1是阻塞,0是非阻塞,1000是每隔1秒...
            while (true)
            {
                LoopOnce(timeout);
            }
        }
        ~EpollServer()
        {
            if (_listensock >= 0)
                close(_listensock);
            if (_epfd >= 0)
                close(_epfd);
            if (_revs)
                delete[] _revs;
        }
    private:
        int _listensock;
        int _epfd;
        uint16_t _port;
        struct epoll_event *_revs; // 就绪的事件
        int _revs_num;
        func_t _HandlerRequest;
    };
}

#endif